# -*- coding: utf-8 -*-
from django.utils.translation import ugettext_lazy as _
from google.appengine.ext import db
from django.utils import simplejson as json
import freebase
from django.http import HttpResponse
from settings import *
from app_settings import *
import logging

class FreebaseRetriever():
    """
    Generic functions for all Freebase retrievers
    """

    COLUMNS_TO_SORT = ('has_products', 'has_develops_treatments_for_disease', 'has_area_of_expertise')

    ID_NAME_KEYS = {
        'has_area_of_expertise': 'technology',
        'has_develops_treatments_for_disease': 'disease',
        'has_products': 'product',
        'has_company_involved': 'company',
        'has__medicine_disease_includes_diseases': 'disease',
        'has_therapeutic': 'therapeutic'}

    def __init__(self):
        self.fms = freebase
        self.query = {}
        self.filter, self.additional_columns, self.sorting_field = (None, None, None)
        # Keys of field that consist of complex objects which has both 'id' and 'name' field
        # { key: page_url }

    @property
    def query(self):
        return self.query

    def set_filter(self, data):
        """
        Setter for 'filter' variable
        """
        if not isinstance(data, dict):
            raise ValueError
        self.filter = data
        if self.filter:
            self.query[0].update(self.filter)
        else:
            self.query[0].update({'limit': ROWS_LIMIT})
        return self

    def include_columns(self, cols):
        """
        Derive a list of column and transform it to dict
        """
        if not isinstance(cols, list):
            raise ValueError
        r = {}
        for col in cols:
            r[col] = []
        self.additional_columns = r or None
        return self

    @classmethod
    def _transform_column_names(cls, entries):
        """
        Replaces all ":" and "/" in column name
        """
        def transform(entry):
            if not isinstance(entry, dict):
                raise ValueError, 'expected type <dict>'
            r = {} # Result
            for key in entry:
                if ":" in key or '/' in key:
                    key_without_colon = key.replace(":", "_").replace('/', '_')
                    r[key_without_colon] = entry[key]
                else:
                    r[key] = entry[key]
                    #r.pop(key)
            return r

        return map(lambda x: transform(x), entries)

    @classmethod
    def _add_links(cls, freebase_answer):
        """
        Add links to internal site pages (as /company/ or /techonology/) to results set.
        """
        r = [] # Result
        for entry in freebase_answer:
            if entry.has_key('_common_topic_image') and len(entry['_common_topic_image'])>0:
                entry['image'] = "".join(("http://www.freebase.com/api/trans/raw", entry.pop('_common_topic_image')[0]['id'])).strip()                
            if entry.has_key('_common_topic_webpage') and len(entry['_common_topic_webpage'])>0:
                entry['website'] = entry.pop('_common_topic_webpage')[0]['uri']
            for key in cls.ID_NAME_KEYS:
                if entry.has_key(key):
                    entry[key] = map(lambda x: "<a href=\"/%s%s\">%s</a>" % (cls.ID_NAME_KEYS[key], x['id'], x['name']),
                        filter(lambda x: x['name'], entry[key]))
            r.append(entry)
        return r

    @classmethod
    def _add_article_content(cls, freebase_answer):
        """
        Retreive article content fro freebase. Split it on first 100 chars and a last part.
        Add first 100 chars as 'article_head' key and a last part as 'article_tail'
        """
        r = [] # Result
        for entry in freebase_answer:
            if entry.has_key('_common_topic_article') and len(entry['_common_topic_article']) > 0:
                entry['article'] = freebase.blurb(entry.pop('_common_topic_article')[0]['id'])
                head = entry['article'][:100].rsplit(' ',1)[0] # first 100 chars
                entry['article_head'] = head
                entry['article_tail'] = entry['article'].partition(head)[-1]
            r.append(entry)
        return r

    @classmethod
    def _sort_cols(cls, freebase_answer):
        """
        Sort columns of resulting table
        """
        r = [] # Result
        for entry in freebase_answer:
            sorted_entry = entry
            for key in cls.COLUMNS_TO_SORT:
                if entry.has_key(key):
                    sorted_entry[key] = filter(lambda x: x != "", sorted_entry[key])
                    sorted_entry[key].sort()
            r.append(sorted_entry)
        return r

    def sort_by(self, field):
        """
        Setter for sorting_field variable
        """
        self.sorting_field = field
        return self

    def _sort_rows(self, freebase_answer):
        """
        Sort freebase answer by specifield field (for example 'name')
        """
        r = freebase_answer # Result
        def sort_dict(x,y):
            """
            Compare function for sort() using key 'name'
            """
            if x[self.sorting_field]>y[self.sorting_field]:
                return 1
            elif x[self.sorting_field]<y[self.sorting_field]:
                return -1
            else:
                return 0

        if self.sorting_field:
            r.sort(cmp=sort_dict)

        return r




class CompaniesRetriever(FreebaseRetriever):
    """
    Search techonologies and fetch results from Freebase DB
    """

    def __init__(self):
        FreebaseRetriever.__init__(self)
        self.query = [{"type" : "".join((BIOVENTURIST_DIR, "science_or_technology_company")),
                  "name" : None,
                  "id" : None,
                  "has:id" : [],
                  "/common/topic/article" : [{"limit" : 1, "optional" : True, "id" : None }],
                  "/common/topic/image" : [{"limit" : 1, "optional" : True, "id" : None }],
                  "/common/topic/webpage" : [{"limit" : 1, "optional" : True, "id" : None, "uri": None }],
                  "has:area_of_expertise" : [{}],
                  "market_analysis": [],
                  "has:products" : [{}],
                  "has:develops_treatments_for_disease" : [{}],
                  }]

    def get(self):

        if self.additional_columns: self.query[0].update(self.additional_columns)

        response = list(self.fms.mqlread(self.query))

        r = self._sort_rows(
                self._sort_cols(
                        self._add_article_content(
                            self._add_links(
                                self._transform_column_names(
                                    response)))))
        return r




class TechnologiesRetriever(FreebaseRetriever):
    """
    Search techonologies and fetch results from Freebase DB
    """

    def __init__(self):
        FreebaseRetriever.__init__(self)
        self.query = \
            [{
                'type': ''.join((BIOVENTURIST_DIR, 'technology_class')),
                'name': None,
                'has:company_involved': [{'name': None, 'id': None}],
                'has:related_to_disease_or_medical_condition': [], # FIXME Can't find this information in database
            }]

    def get(self):

        if self.additional_columns: self.query[0].update(self.additional_columns)

        response = list(self.fms.mqlread(self.query))

        r = self._sort_rows(
                self._sort_cols(
                        self._add_article_content(
                            self._add_links(
                                self._transform_column_names(
                                    response)))))
        return r


class MedicalConditionsRetriever(FreebaseRetriever):
    """
    Search Medical Conditions and fetch results from Freebase DB
    """

    #[{
        #'name':null,
        #'type':'/base/bioventurist/bv_medical_condition',
        #'/medicine/disease/causes': [],
        #'/medicine/disease/includes_diseases': [{'id': null, 'name': null, 'optional': true}],
        #'therapeutics': [{'therapeutic': [{'id': null, 'name': null}], 'optional': true}],
        #'company_involved': [{'id': null, 'name': null}],
        #'limit': 3,
    #}]

    def __init__(self):

        FreebaseRetriever.__init__(self)
        self.query = \
            [{
                'type': ''.join((BIOVENTURIST_DIR, 'bv_medical_condition')),
                'name': None,
                'has:/medicine/disease/causes': [],
                'has:/medicine/disease/includes_diseases': [{'id': None, 'name': None, 'optional': True}],
                'has:therapeutics': [{'therapeutic': [{'id': None, 'name': None}], 'optional': True}],
                'has:company_involved': [{'id': None, 'name': None}],
                'limit': 1,
            }]

    @classmethod
    def _format_specific(cls, entries):
        """
        Format specific field for Medical Conditions
        """
        def transform_therapeutics(entry):
            for k in entry:
                if k == 'has:therapeutics':
                    r = [] # Transformed entry
                    for x in [x['therapeutic'] for x in entry[k]]:
                        for y in x:
                            r.append('<a href="/therapeutic%s">%s</a>' % (y['id'], y['name']))
                    entry[k] = r
            return entry

        return map(lambda x: transform_therapeutics(x), entries)

    def get(self):

        if self.additional_columns: self.query[0].update(self.additional_columns)

        response = list(self.fms.mqlread(self.query))

        r = self._sort_rows(
                self._sort_cols(
                    self._add_article_content(
                        self._add_links(
                            self._transform_column_names(                           
                                self._format_specific(
                                    response))))))
        return r

